<?php

namespace App\Services\Sms;

use App\Enums\ResponseCode;
use App\Enums\SmsEnum;
use App\Exceptions\BusinessException;
use App\Models\SmsBlacklist;
use App\Models\SmsSendlog;
use App\Services\AbstractBaseService;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class VerifyService extends AbstractBaseService
{


    /**
     * 检测两次发送的间隔(用户触发的才需要调用)。
     *
     * @param string $mobile 手机号码
     *
     * @return void true - 不受时间间隔限制、false - 受时间间隔所限
     * @throws BusinessException
     */
    public static function checkSendInterval(string $mobile)
    {
        $interval = config('sms.interval');
        $cacheKey = SmsEnum::SMS_INTERVAL.":".$mobile;
        $sendTsp  = Cache::get($cacheKey);
        $time     = time();
        if ($sendTsp > 0 && (($time - $sendTsp) < $interval)) {
            self::exception( ResponseCode::SERVICE_UNAVAILABLE,trans("两次发送间隔不能小于:attribute秒",['attribute'=>$interval]));
        } else {
            Cache::put($cacheKey, $time, $interval); // 记录最后一次发送的时间。
        }
    }

    /**
     * 检测当日 IP 发送是否超限。
     *
     * @param string $ip
     * @param string $sendKey 发送的模版
     * @param integer $driveCut 发送的驱动
     * @return void
     * @throws BusinessException
     */
    public static function checkDayIpTimes(string $ip, string $sendKey, int $driveCut)
    {
        $ipSendMax = config('sms.ip_send_max');
        if ($ipSendMax > 0) {
            $datetime = today();
            $sql = 'SELECT COUNT(1) AS count FROM `sms_sendlog` AS a '
                . 'LEFT JOIN `sms_tpl` AS b ON(a.tpl_id=b.id) '
                . 'WHERE a.ip = :ip AND a.created_at > :created_at AND b.send_key=:send_key AND b.trigger_type = :trigger_type AND a.drive_cut= :drive_cut';
            $params = [
                'ip'           => $ip,
                'created_at'       => $datetime,
                'send_key'       => $sendKey,
                'drive_cut'    => $driveCut,
                'trigger_type' => SmsEnum::TRIGGER_TYPE_USER
            ];
            $result = DB::selectOne($sql, $params);
            $count  = $result ? $result->count : 0;
            if ($count >= $ipSendMax) {
                self::exception( ResponseCode::SERVICE_UNAVAILABLE,trans("您的IP今天已发送超过:attribute次",['attribute'=>$count]));
            }
        }
    }

    /**
     * 检测当日账号发送次数是否超限。
     *
     * @param $mobile
     * @throws BusinessException
     */
    public static function checkDayAccountTimes($mobile)
    {
        $mobileSendMax = config('sms.account_send_max');
        if ($mobileSendMax > 0) {
            $datetime = today();
            $where    = [
                'mobile' => $mobile,
                'created_at' => ['>', $datetime]
            ];
            $count = SmsSendlog::query()->count($where);
            if ($count >= $mobileSendMax) {
                self::exception( ResponseCode::SERVICE_UNAVAILABLE,trans("您的帐号今天已发送超过:attribute次",['attribute'=>$mobileSendMax]));
            }
        }
    }

    /**
     * 是否为内部手机号码。
     *
     * -- 内部手机号码不受各种限制。
     *
     * @param string $mobile  手机号码或者邮箱。
     * @return bool true-内部手机号、false-不是内部手机号。
     */
    public static function isInsideAccount(string $mobile): bool
    {
        $accountWhiteList = config('sms.inside_accounts');
        if (strlen($accountWhiteList) === 0) {
            return false;
        }
        $accountWhiteList = explode(',', $accountWhiteList);
        if (in_array($mobile, $accountWhiteList)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 是否为黑名单手机号。
     *
     * @param string $mobile  手机号码||邮箱。
     * @return bool true-在黑名单、false-不在黑名单。
     */
    public static function isBlackListAccount(string $mobile): bool
    {
        $mobileArr = self::allBlacklistAccountResult();
        return in_array($mobile, $mobileArr);
    }

    /**
     * 全部黑名单数据。
     *
     * -- 通过缓存提高并发速度。
     *
     * @return array
     */
    protected static function allBlacklistAccountResult(): array
    {
        $cache = Cache::get(SmsEnum::BLACKLIST_ACCOUNT_CACHE_KEY);
        if ($cache === false || $cache === null) {
            $result  = SmsBlacklist::query()->pluck('mobile')->toArray();
            Cache::put(SmsEnum::BLACKLIST_ACCOUNT_CACHE_KEY, json_encode($result));
            return $result;
        } else {
            return json_decode($cache, true);
        }
    }

}
